#include "CCloud.h"
#include "CPlatform.h"
#include "CPlayer.h"
#include "CTimer.h"
#include "CRender.h"
#include "CAnimationEngine.h"

///////////////////////////////////////////
//	RAIN MAN SETTINGS					///
#define RAINDROP_SIZE .4f
#define MIN_RAINDROP_SPD 5.0f
#define MAX_RAINDROP_SPD 7.0f
#define MAX_LIFE 0.85f
///////////////////////////////////////////
CCloud::CCloud()
{
	m_unCurrState = IDLE;
	m_unType = CLOUD;
	m_fEmitTimer = 0;
	m_fEmitRate = 0.05f;
	m_vRainDrops.resize(30);	//Reuse Raindrops
	m_fHeightFromPlayer = 5;
	m_fRadius = 2.5f;

	m_fTheta = 0.0f;

	StartRain();

	m_Quad.MakeShape(Vec2(-2.5f, -2.5f), Vec2(2.5f, 2.5f), 1);

	m_vAnimations.push_back(CAnimationEngine::GetInstance()->LoadAnimation(Cloud_Idle));
	m_vAnimations.push_back(CAnimationEngine::GetInstance()->LoadAnimation(Cloud_Eat));
	m_vAnimations.push_back(CAnimationEngine::GetInstance()->LoadAnimation(Cloud_Lightning));
	m_vAnimations.push_back(CAnimationEngine::GetInstance()->LoadAnimation(Cloud_LightningBolt));

	CRainDrop::s_QUAD.MakeShape( Vec2(-RAINDROP_SIZE, -RAINDROP_SIZE), Vec2(RAINDROP_SIZE, RAINDROP_SIZE), 1);
}

CCloud::~CCloud()
{ 
	m_pPlayer->Release(); 
}

void CCloud::Update(float fElapsed)
{
	m_Pos = Vec3(0.0f, m_fHeightFromPlayer + m_pPlayer->m_Pos.Length(), 0.0f) * Mat4::GetRotateZ(m_fTheta);
	CalculateTheta();

	bool bStillPlaying = m_vAnimations[m_unCurrState]->Play(CTimer::GetInstance()->GetElapsedTime());
	if (m_unCurrState == BOLT)
		m_vAnimations[m_unCurrState]->Play(CTimer::GetInstance()->GetElapsedTime());

	if (!bStillPlaying && m_unCurrState == EAT)
	{
		m_unCurrState = IDLE;
	}

	//Position yourself above the player
	Vec3 Up = m_pPlayer->m_Pos;				//TODO: I want this to float up and down to catch up with the player
	Up.Normalize();									// But I may be too tired to do figure it out right now...
	
	// before we normalize, catch the length so i know how far away the player is from the cloud
	// vector from (cloud to player)'s length
	float length = (m_pPlayer->m_Pos - m_Pos).Length();
	// now we manually normalize
	// if the length is more than the distance from the player, we need restore the cloud to that position "smoothly" overtime
	float actualdistance = m_fHeightFromPlayer - length;

	actualdistance *= fElapsed;

	m_Pos = Up * (m_fHeightFromPlayer/* + actualdistance*/) + m_pPlayer->m_Pos;

	//Emit Raindrops
	m_fEmitTimer += fElapsed;
	while (m_fEmitTimer >= m_fEmitRate)
	{
		m_fEmitTimer -= fElapsed;
		CreateRainDrop(-Up);
	}

	for( unsigned int i = 0; i < m_vRainDrops.size(); i++) {
		m_vRainDrops[i].Update( fElapsed );
	}
}

bool CCloud::CheckCollision(CBase *pBase)
{
	for( unsigned int i = 0; i < m_vRainDrops.size(); i++) 
	{
		m_vRainDrops[i].CheckCollision(pBase);
	}
	return true;
}

void CCloud::Render()
{
	CRender::GetInstance()->DrawTex(m_vAnimations[m_unCurrState]->GetCurrentTextureHandle(), &m_Quad, Vec2(m_Pos.x, m_Pos.y), 2, m_pPlayer->m_fTheta);
	if (m_unCurrState == BOLT)
	{
		Vec3 BoltPos = -m_Pos;
		BoltPos.Normalize();
		BoltPos = BoltPos * 1.5f + m_Pos;
		CRender::GetInstance()->DrawTex(m_vAnimations[BOLT + 1]->GetCurrentTextureHandle(), &m_Quad, Vec2(BoltPos.x, BoltPos.y), 1, m_pPlayer->m_fTheta);
	}
	for (unsigned int i = 0; i < m_vRainDrops.size(); i++) 
	{
		m_vRainDrops[i].Render();
	}
}

void CCloud::StartRain()
{
	for (unsigned int i = 0; i < m_vRainDrops.size(); i++)
	{
		m_vRainDrops[i].m_fAge = RAND_FLOAT(0.0f, MAX_LIFE);
		m_vRainDrops[i].m_Pos = m_Pos + Vec3(RAND_FLOAT(-m_fRadius, m_fRadius), RAND_FLOAT(-15, 0), 0);
		m_vRainDrops[i].m_Vel = Vec3(0, -1, 0) * RAND_FLOAT(MIN_RAINDROP_SPD, MAX_RAINDROP_SPD);
		m_vRainDrops[i].m_fTheta = 0;
	}
}

void CCloud::CreateRainDrop(Vec3 &DownVec)
{
	for (unsigned int i = 0; i < m_vRainDrops.size(); i++)
	{
		if (m_vRainDrops[i].m_fAge > m_vRainDrops[i].m_fLifeSpan)
		{
			m_vRainDrops[i].m_fAge = RAND_FLOAT(0.0f, 0.1f);
			m_vRainDrops[i].m_Pos = m_Pos + Vec3(RAND_FLOAT(-m_fRadius, m_fRadius), RAND_FLOAT(-m_fRadius * 0.75f, m_fRadius * 0.75f), 0);
			m_vRainDrops[i].m_Vel = DownVec * RAND_FLOAT( MIN_RAINDROP_SPD, MAX_RAINDROP_SPD );	// Multiply this by a speed value
			m_vRainDrops[i].m_fTheta = m_pPlayer->m_fTheta;
			return;
		}
	}
}

/////////////////////////
// RainDrop
/////////////////////////

Texture* CRainDrop::s_pTexture = NULL;
CShape CRainDrop::s_QUAD;

CRainDrop::CRainDrop()
{
	m_unType = RAINDROP;
	m_fLifeSpan = MAX_LIFE;
	m_fAge = m_fLifeSpan + 1;
}

void CRainDrop::Update(float fElapsed)
{
	//if (m_fAge < m_fLifeSpan)
	//{
		CBase::Update(fElapsed);
		CalculateTheta();

		m_fAge += fElapsed;
	//}
}

void CRainDrop::Render()
{
	CRender::GetInstance()->DrawTex(s_pTexture, &s_QUAD, Vec2( m_Pos.x, m_Pos.y ), -0.1f, m_fTheta);
}

bool CRainDrop::CheckCollision(CBase *pBase)
{

	if (pBase->m_unType == NOODLE && !((CPlatform*)pBase)->m_bVisible)
	{
		float fHeight = m_Pos.Length()-2.0f;
		if (fHeight >= ((CPlatform *)pBase)->m_fInnerLimit && fHeight <= ((CPlatform *)pBase)->m_fOuterLimit &&
			m_fTheta-.2f <= ((CPlatform *)pBase)->m_fThetaFirst && m_fTheta+.2f >= ((CPlatform *)pBase)->m_fThetaSecond)
		{
			m_fAge = m_fLifeSpan + 1;
			((CPlatform*)pBase)->m_bVisible = true;
			return true;
		}
	}

	return false;
}